#include "swoole.h"
#include "Server.h"

static int swFactoryProcess_start(swFactory *factory);
static int swFactoryProcess_notify(swFactory *factory, swDataHead *event);
static int swFactoryProcess_dispatch(swFactory *factory, swDispatchData *buf);
static int swFactoryProcess_finish(swFactory *factory, swSendData *data);
static int swFactoryProcess_end(swFactory *factory, int fd);
static int swFactoryProcess_shutdown(swFactory *factory);

int swFactoryProcess_create(swFactory *factory, int worker_num){
	swFactoryProcess *object;
	object = SwooleG.memory_pool->alloc(SwooleG.memory_pool,sizeof(swFactoryProcess));

	factory->object = object;
	factory->start = swFactoryProcess_start;
	factory->dispatch = swFactoryProcess_dispatch;
	factory->notify = swFactoryProcess_notify;
	factory->finish = swFactoryProcess_finish;
	factory->end = swFactoryProcess_end;
	factory->shutdown = swFactoryProcess_shutdown;

	return 0;
}

static int swFactoryProcess_shutdown(swFactory *factory){
	int status;
	swServer *serv = factory->ptr;

	if (swKill(serv->gs->manager_pid, SIGTERM) < 0)
    {
        printf("kill(%d) failed.", serv->gs->manager_pid);
    }

    if (swWaitpid(serv->gs->manager_pid, &status, 0) < 0)
    {
        printf("waitpid(%d) failed.", serv->gs->manager_pid);
    }

	return 0;
}

static int swFactoryProcess_start(swFactory *factory){
	swServer *serv = factory->ptr;
	serv->reactor_pipe_num = serv->worker_num / serv->reactor_num;
	if(swManager_start(factory) < 0){
	}
}

static int swFactoryProcess_finish(swFactory *factory, swSendData *resp){
	int session_id = resp->info.fd;
	int sendn,ret;
	swServer *serv = factory->ptr;

	swConnection *conn = swServer_connection_verify(serv, session_id);
	if(!conn){
		printf("connection dose not exist\n");
		return -1;
	}

	swEventData ev_data;
	ev_data.info.fd = session_id;
	ev_data.info.type = resp->info.type;
	memcpy(ev_data.data, resp->data, resp->info.len);
	ev_data.info.len = resp->info.len;
	ev_data.info.from_id = conn->from_id;
	sendn = ev_data.info.len + sizeof(resp->info);

	ret = swWorker_send2reactor(&ev_data, sendn, session_id);

	return ret;
}

static __thread struct
{
	long target_worker_id;
	swDataHead _send;
} sw_notify_data;

static int swFactoryProcess_notify(swFactory *factory, swDataHead *ev){
	memcpy(&sw_notify_data._send, ev, sizeof(swDataHead));
	sw_notify_data._send.len = 0;
	sw_notify_data.target_worker_id = -1;

	return factory->dispatch(factory,(swDispatchData *)&sw_notify_data);
}

static int swFactoryProcess_dispatch(swFactory *factory, swDispatchData *task){
	uint32_t send_len = sizeof(task->data.info) + task->data.info.len;
	int target_worker_id;
	swServer *serv = SwooleG.serv;
	int fd = task->data.info.fd;

	if(task->target_worker_id < 0){
		target_worker_id = swServer_worker_schedule(serv, fd, &task->data);
	}else{
		target_worker_id = task->target_worker_id;
	}

	printf("target_worker_id = %d and fd = %d\n",target_worker_id,fd);
	printf("worker num is %d and reactor num is %d\n",serv->worker_num,serv->reactor_num);

	if(target_worker_id < 0){
		return 0;
	}

	swConnection *conn = swServer_connection_get(serv, fd);

	//converted fd to session_id and why???
	task->data.info.fd = conn->session_id;
	task->data.info.from_fd = conn->from_fd;
	
	return swReactorThread_send2worker((void *) &(task->data), send_len, target_worker_id);
}

static int swFactoryProcess_end(swFactory *factory, int fd){
	swServer *serv = factory->ptr;
	swSendData _send;
	swDataHead info;

	bzero(&_send, sizeof(_send));
	_send.info.fd = fd;
	_send.info.len = 0;
	_send.info.type = SW_EVENT_CLOSE;

	swConnection *conn = swWorker_get_connection(serv, fd);

	if(serv->onClose != NULL){
		info.fd = fd;
		info.from_fd = conn->from_fd;
		serv->onClose(serv,&info);
	}

	return factory->finish(factory,&_send);
}
